/**
 * 
 */
package jnzb.control.remote;

import java.io.File;
import java.net.MalformedURLException;
import java.rmi.RemoteException;
import java.rmi.ServerException;

import jnzb.control.Configuration;
import jnzb.control.Controller;
import jnzb.control.events.InfoEventProcessor;
import jnzb.control.util.SimpleFileLogger;

/**
 * Handles the launching of the remote object and the subsequent calls from the
 * remote object when received. This will do the extra validation necessary
 * before calling the controller.
 * 
 * @author AA1
 * 
 */
public class RemoteController implements Runnable {

	private Controller controller;

	private JNZBRemoteAgentListener remoteListener = null;

	private InfoEventProcessor infoProcessor;

	private String filename = null;

	private boolean keepRunning = true;

	public RemoteController(Controller controller) {
		this.controller = controller;
		this.infoProcessor = controller.getInfoProcessor();
	}

	/**
	 * Reads the config and launch the remote agent listener if we're using the
	 * remote agent
	 */
	public void launch() {
		if (Configuration.getInstance().agentEnabled()) {
			createAndExportRemoteListener();
			new Thread(this).start();
		} else {
			infoProcessor.info("Not listening for NZB via double-click");
		}
	}

	/**
	 * Receive a call from the remote agent listener. Perform any necessary
	 * validation before handing over to the controller. Agent will ensure that
	 * this is a proper NZB
	 * 
	 * @param filename
	 */
	public synchronized void queueNZB(String filename) {
		this.filename = filename;
		notifyAll();
	}

	/**
	 * Stops the thread
	 */
	public synchronized void stop() {
		this.keepRunning = false;
		notifyAll();
	}

	/**
	 * Main loop. Keeps going until stop() is called
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public synchronized void run() {
		int rmiPort = Configuration.getInstance().getAgentPort();
		infoProcessor.info("Listening for NZBs via double-click on port " + rmiPort);
		while (keepRunning) {
			if (this.filename != null) {
				controller.loadNZBEvent(new File(this.filename), true);
				int slash=this.filename.lastIndexOf("\\");
				if (slash>-1){
					this.filename = this.filename.substring(slash+1);
				}
				infoProcessor.info("Queueing " + filename
						+ " from double click");
				this.filename=null;
			} else {
				try {
					wait();
				} catch (InterruptedException e) {
					// Just go around again
				}
			}
		}
	}

	/**
	 * Obtains the remote session manager object and exports it ready for remote
	 * access
	 * 
	 * @throws ServerException
	 * 
	 */
	private void createAndExportRemoteListener() {
		try {
			// Get the session manager instance
			if (this.remoteListener == null) {
				this.remoteListener = new JNZBRemoteAgentListener(this);
			}

			// Create the RMI directory
			createRMIDirectory();

			// Bind the session manager into the directory.
			bindSessionManager();
		} catch (RemoteException rex) {
			rex.printStackTrace();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Creates the RMI registry programatically.
	 * 
	 * @throws RemoteException
	 *             - if there is a problem creating the directory
	 */
	private void createRMIDirectory() throws RemoteException {
		// Get the port that we're running the server on from the configuration.
		// This has been pre-validated
		int rmiPort = Configuration.getInstance().getAgentPort();
		try {
			java.rmi.registry.LocateRegistry.createRegistry(rmiPort);
		} catch (java.rmi.server.ExportException ee) {
			// We don't mind about this exception as this is what we are trying
			// to achieve anyway
			SimpleFileLogger.getInstace().writeRaw("Unable to create RMI registry - " + ee.getMessage());
		}
	}

	/**
	 * Bind the session manager into the RMI registry
	 * 
	 * @throws RemoteException
	 *             - if there is a problem binding the session manager into the
	 *             registry
	 * @throws MalformedURLException
	 *             - if the URL of the registry is incorrect
	 */
	private void bindSessionManager() throws RemoteException,
			MalformedURLException {
		// Since the session manager extends UnicastRemoteObject, there is no
		// need to export it.

		// Use of rebind means that we will only overwrite existing object bound
		// to the same name
		java.rmi.Naming.rebind(Configuration.getInstance().getRemoteLocation(),
				this.remoteListener);

	}

}
